﻿#include "Stack.h"
#include"Date.h"
#include<iostream>
#include<vector>
#include<list>

using namespace std;
using std::cout;
using std::endl;


//初始化列表
// myqueue(ing a)
// :x（a）//x = a
// {
// }
//对每个成员：自定义类/内置类可以一起初始化（用一个: （）  , （） 隔开的列表作为函数的后缀）
////可以一部分写成函数体{}内
//可以理解为成员定义列表/声明在private
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 3)//不需传参的默认构造函数
	//Stack(size_t capacity)//此时变成了需要传参数的函数/非默认构造：需要显示的写构造函数
	{
		cout << "Stack(size_t capacity = 3)" << endl;
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("申请失败");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}

	//Stack st2=st1;
	Stack(const Stack& st)
		//开辟相同大小的空间，并将对应位置的数据拷贝过来
	{
		cout << "Stack(const Stack& st)" << endl;
		_array = (DataType*)malloc(sizeof(DataType) * st._capacity);
		if (NULL == _array)
		{
			perror("申请失败");
			return;
		}
		memcpy(_array, st._array, sizeof(DataType) * st._size);
		//拷贝后容量和大小也要改变
		_capacity = st._capacity;
		_size = st._size;
	}

	void Push(DataType data)
	{
		_array[_size] = data;
		_size++;
	}

	~Stack()
	{
		cout << "~Stack()" << endl;
		if (_array)
		{
			if (_array)
			{
				free(_array);
				_array = NULL;
				_capacity = 0;
				_size = 0;
			}
		}
	}
private:
	DataType* _array;
	int _capacity;
	
	//缺省值（就是给初始化列表中的（）内部）：
	//意义就是在默认构造中，无参函数调用，且外部没有传参时的默认参数值
	int _size = 0;
};

class MyQueue
{
public:
	//初始化列表
	//无论显示写或否，都会自动生成初始化列表跑：自定义类型调用默认构造/无（无参的）默认构造：则报错
	//先走初始化列表 + 再走函数体
	MyQueue()
		//可以混用：有默认的构造函数，也可以传参数初始化
		:_size(1)
		,_pushst(10)
		,_ptr((int*)malloc(8))//int* ptr=((int*)malloc(8));
		,_x()//const int _x = 1;(这里的1被当作缺省值/如果初始化么有传参，则用1来初始化)
	{
		memset(_ptr, 0, 40);
	}

	////只能显示的写构造：
	// 
	//这时要用到初始化列表：
	//传参格式 ：（冒号）开始 ,(逗号)分割
	//Stack _pushst; 和 Stack _popst;都缺少默认的构造
	//
	 
	//初始化
	//成员的定义:(有的成员可以不写)  可以在初始化列表初始化，也可以在函数体内初始化
	//1，引用 2，const 3，没有默认构造函数的自定义类型成员
	//MyQueue(int n ,int & xx)
	//	//也是初始化，不用写类型
	//	:_pushst(n)//（冒号）开始  用n来构造
	//	,_popst(n)//调用Satck的有参构造函数 Satck（n）
	//	,_size(0)//(逗号)分割//_size = 0
	//	,_x(1)//_x = 1
	//	,_ref(xx)//_ref = xx
	//{
	//	//_size = 0 ;//可以一部分写成函数体
	//	//_x = 1;//❌：只能在初始化列表初始化//定义的时候就初始化
	//}

private:
	//声明：两个自定义类的栈：他俩没有默认的构造/只有显示的构造
	//！！！因此要使用这两个无默认构造的类来->另一个类：
	//！！！另一个类也无法生成默认构造，需要显示的写
	Stack _pushst;
	Stack _popst;
	int _size;

	//const int _x;//const修饰的变量（全局），也必须在初始化列表初始化
	//**const不能在初始化函数体内部初始化{ ... } 只能在初始化列表里:,
	//与上面的_size不同

	//！！！const修饰的变量，必须在第一次定义的时候初始化
	const int _x = 1;
	//这里还是声明：当作缺省值给MyQueue函数调用

	//int& _ref;//引用也要在定义的时候初始化（别名一定要说明是谁的别名）
	int* _ptr;
};

/*
int main()
{
	//int xx = 0;//int& ry;
	//定义一个用于初始化引用的参数

	//定义：含两个栈类和一个int类型的（自定义队列）
	//MyQueue q1(10,xx);//不写初始化，编译器会生成：默认的构造（不用传参的构造）
	//对自定义类型，会去调用这个自定义类型的默认构造
	//编译器自动生成的构造函数对于内置类型的成员变量不做处理，
	
	//如果此时Stack（自定义类型） ！！！不具备默认构造：14
	//MyQueue也无法生成对应的默认构造函数：
	//只能显示的写MyQueue的构造

	//无参的初始化列表时是20个
	// 传入不同的参数/和不传参数的区别
	//
	MyQueue q2;

	//理解为MyQueue的成员在初始化列表定义

	//int& ry = xx;//引用要在定义的时候初始化

	return 0;
}
*/

/*
//初始化列表初始化顺序：声明的顺序，而不是（列表上）出现的顺序
class A
{
public:

	A(int a)//a=1
		:_a1(a)//_a1 = a
		,_a2(_a1)//_a2 =_a1
		//按照声明的顺序：先进行的是_a2 =_a1，然后_a1 = a
		//这时：由于_a1（随机值）：_a2 == 随机值 ，_a1 = 1
	{
	
	}
	
	void Print()
	{
		cout << _a1 << "" << _a2 << endl;//1 随机值
		
	}

private:
	int _a2 ;
	int _a1;
};

int main()
{
	A aa(1);
	aa.Print();

	//？问输出的情况：//1 随机值
	//初始化的顺序为声明顺序
	return 0;
}
*/

/*
//能够实现内置类型转换成自定义类型
class A
{
public:
	//能够实现内置类型转换成自定义类型：
	// 单参数的构造函数
	
	A(int a)
	//explicit A(int a) //如果不想隐式类型转换;就加上explicit
		:_a(a)
	{
		//直接构造：
		cout << "A(int a)" << endl;
	}
	
	A(const A& aa)
		:_a(aa._a)//aa类里的内置类型a(成员变量)
	{
		//拷贝构造：
		cout << "A(const A& aa)" << endl;
	}

	//多参数构造：
	A(int a1, int a2)
		:_a(0)
		,_a1(a1)
		,_a2(a2)
	{}
	
private:
	int _a;
    int _a1;
	int _a2;
};
*/


/*
int main()
{
	A aa1(1);//正常的构造
	A aa2 = aa1;//拷贝构造

	A aa3 = 3;//？
	A aa4 = 3.3;
	//A aa5 = "222222";//字符串不行

	//隐式类型转换：
	//内置类型转换成自定义类型----由单参数的构造函数支持的
	// 
	//int i = 10;   ->  double d = i;//举个例子：类型转换
	//中间会产生临时变量（使用临时变量❌：加上const：临时变量具有常性 const double& rd = i;）
	//	A aa3 = 3;的含义：用3构造一个A的临时对象，再用这个临时对象拷贝构造aa3
	// 编译器遇到连续的构造+拷贝构造->直接优化为直接构造（跳过拷贝）

	//****对两种类型间的转换：要注意常性的临时变量的产生，要加上const修饰，避免权限的放大
	const A& raa = 3;//A类型不能引用3（int类型）：因为临时变量具有常性（加上const）

	//这里没有连续的构造和拷贝构造：只有构造：用3构造的A（所以不会被优化：）

	//多参数的初始化：
	A aaa1(1, 2);
	//A aaa1 = (1, 2);//❌不能像单参数一样传递值构造
	//上一行如果不屏蔽单参数的初始化：相当于传进去的是逗号表达式的后操作数2
	A aaa1 = {1, 2};// 运行的过程和 A aa3 = 3;（单参数构造）类似
	//都是先构造临时变量，再拷贝构造
	
	//不产生拷贝构造的：类型引用 + 加const
	const A& aaa1 = { 1, 2 };//可以省略=号

	return 0;
}
*/
//多参数加{}，单参数直接写

/*
class Stack1
{
public:
	void Push(const A& aa)//加上引用没有了拷贝构造
	{
		
	}
};
*/


//
//class string
//{
//public:
//	string(const char* str)
//	{ }
//};

/*
int main()
{
//A a5(1);//先构造：1
	Stack1 st;//再创建：对A的函数
//	st.Push(a5);//使用函数
	//结果：有拷贝构造
	//A(int a)
	//A(const A & aa)
	//建议：函数参数加上引用：减少拷贝构造test1.cpp  59

	st.Push(2);//跳过构造1，直接将1隐式类型转换成A类


	list<string>lt;
	string s1("1111");//有拷贝构造
	lt.push_back(s1);

	lt.push_back("1111");//跳过拷贝构造 
	//隐式类型转换

	//多参数也支持隐式类型转换
	//插入两个参数的A
	A aa1(1, 2);
	st.Push(aa1);//构造+拷贝构造（无优化）
	//  或
	st.Push({ 1,2 });//只有构造


	return 0;
}
*/

/*
class BB
{
public:
	BB()
	{

	}

private:
	//缺省值：给初始化列表用的
	//给缺省值的多种方式
	int _b1 = 1;
	int* _ptr = (int*)malloc(40);
	Stack _pushst = 10;

	A _a1 = 1;//包含隐式类型转换
	A _a2 = { 1,2 };
};
*/

/*
int main()
{
	BB bb;

	return 0;
}
*/

//静态成员变量/普通成员变量
//
/*
class A
{
public:
	A() 
	{ 	++_scount;	}
	A(const A& t) 
	{ 	++_scount; }
	//在 构造/拷贝构造 时++
	//析构时--
	~A() 
	{ //--_scount;
	}
	//_scount:如果没有写public到共有全局可以访问：
	//还有一种方法可以访问：静态成员函数GET
	//static修饰：没有this指针：只能访问静态成员
	//不能访问_a1/_a2。。。
	static int GetCount()
	{
		return _scount;
	}

private:
	int _a1;
	int _a2;
//public:
	static int _scount;//❌不能给缺省值：因为缺省值是给初始化列表：初始化成员函数：而static不是成员变量：在静态区
};

//类中只有声明没有定义：在外部加上定义
int A::_scount = 0;

A func()
{
	A aa4;
	return aa4;
}

int main()
{
	A aa1;
	cout << sizeof(aa1) << endl;// 8 :static是全局，不在对象内部：在静态区
	
	//全局时的_scount访问方式:
//	aa1._scount++;//访问成员变量
//  cout << A::_scount << endl;//类域

	//统计A类型的对象一共创建了多少个？
	//所有的对象都要走拷贝构造：在 构造/拷贝构造 时++，析构时--
	A aa2;
	A aa3(aa1);
	
	func();
	//cout << A::_scount << endl;
//5 : 原因传值返回还会生成一个拷贝、
//4：vs 2022优化了

	//静态成员函数GET
	cout << A::GetCount()<< endl;
	return 0;
}
*/









